#include "session.h"
#include "msg_node.h"
#include "server.h"
#include "logic.h"
#include "../../log.h"

#include <boost/asio/co_spawn.hpp>
#include <boost/asio/awaitable.hpp>
#include <boost/asio/detached.hpp>
#include <boost/asio.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/asio/co_spawn.hpp>
#include <cstddef>
#include <cstdint>


Session::Session(boost::asio::io_context& io, Server* server)
:m_iocontext(io)
,m_server(server)
,m_sock(io)
{
    m_uuid = boost::uuids::to_string(boost::uuids::random_generator()());
}

void Session::Start()
{
    boost::asio::co_spawn(m_iocontext, [this, ptr = shared_from_this()]()->boost::asio::awaitable<void>{
        try
        {
            while(!m_is_closed)
            {
                HeadNode::ptr head_node = std::make_shared<HeadNode>();
                //协程就不需要回调函数了
                size_t n = co_await boost::asio::async_read(m_sock, boost::asio::buffer(head_node->m_data.get(), head_node->m_total_len),
                    boost::asio::use_awaitable);
                if(n <= 0)
                {
                    log_info("Session close, ip: {}, cose: {}", m_sock.remote_endpoint().address().to_string(), n);
                    Close();
                    co_return; //用于结束协程并可能返回一个最终值。
                }

                n = head_node->GetHeatInfo();
                if(n != 0)
                {
                    log_error("GetHeatInfo error, ip: {}, code: {}", m_sock.remote_endpoint().address().to_string(), n);
                    Close();
                    co_return;
                }
                
                m_recv_node = std::make_shared<RecvNode>(head_node);
                n = co_await boost::asio::async_read(m_sock, boost::asio::buffer(m_recv_node->m_data.get(), m_recv_node->m_total_len),
                    boost::asio::use_awaitable);
                if(n <= 0)
                {
                    log_info("Session close, ip: {}, cose: {}", m_sock.remote_endpoint().address().to_string(), n);
                    Close();
                    co_return;
                }
                std::shared_ptr<LogicNode> logic_node = std::make_shared<LogicNode>(shared_from_this());
                Logic::GetInstance().AddLogicNode(logic_node);
                // log_debug("Session recv data, ip: {}, data: {}", m_sock.remote_endpoint().address().to_string() ,m_recv_node->m_data.get());
            }
        }
        catch(std::exception& e)
        {
            log_error("Session error: {}", e.what());
        }

    }, boost::asio::detached);
}

void Session::Send(const char* data, uint32_t len, uint32_t id)
{
    std::unique_lock<std::mutex> lock(m_send_mutex);
    size_t size = m_send_queue.size();
    if(size > MAX_SENDQUE)
    {
        log_error("SendQueue is full, ip: {}", m_sock.remote_endpoint().address().to_string());
        return;
    }

    m_send_queue.push(std::make_shared<SendNode>(data, len, id));
    if(size > 0)
    {
        return;
    }
    auto send_data = m_send_queue.front();
    lock.unlock();

    boost::asio::async_write(m_sock, boost::asio::buffer(send_data->m_data.get(), send_data->m_total_len), 
    [this, ptr = shared_from_this()](boost::system::error_code ec, std::size_t len){
        _HeadWrite(ec, len, ptr);
    });
}


void Session::_HeadWrite(boost::system::error_code ec, std::size_t len, std::shared_ptr<Session> self)
{
    try
    {
        if(ec)
        {
            log_error("Session send error, ip: {}, code: {}, message: {}", m_sock.remote_endpoint().address().to_string(), ec.value(), ec.message());
            Close();
            return;
        }
        
        std::unique_lock<std::mutex> lock(m_send_mutex);
        m_send_queue.pop();
        if(m_send_queue.size() > 0)
        {
            auto send_data = m_send_queue.front();
            lock.unlock();
            boost::asio::async_write(m_sock, boost::asio::buffer(send_data->m_data.get(), send_data->m_total_len), 
            [this, ptr = self](boost::system::error_code ec, std::size_t len){
                _HeadWrite(ec, len, ptr);
            });
        }

    }
    catch (const std::exception& e)
    {
        log_error("_HeadWrite error: {}", e.what());
        Close();
        return;
    }
}

void Session::Close()
{
    m_server->DeleteSession(m_uuid);
    m_sock.close();
    m_is_closed = true;
}